These are the proposed changes to XenD that adapt vTPM handling to the
authorEwan Mellor <ewan@xensource.com>
Sat, 28 Oct 2006 16:12:04 +0000 (17:12 +0100)
committerEwan Mellor <ewan@xensource.com>
Sat, 28 Oct 2006 16:12:04 +0000 (17:12 +0100)
document and the implementation in the library. It's implementation is
now similar to VIF and VBD. The implementation passes the first 2 tests
in the vTPM- related tests in the xm-test suite.

Minor conflict resolution by Ewan Mellor.

Signed-off-by: Stefan Berger <stefanb@us.ibm.com>
tools/python/xen/xend/XendAPI.py
tools/python/xen/xend/XendConfig.py
tools/python/xen/xend/XendDomainInfo.py
tools/python/xen/xend/XendError.py
tools/python/xen/xend/server/tpmif.py
tools/python/xen/xm/create.py

index f921b92e9061e67870af9d069fd4235f6094a4c4..8cdb553d87f3cc72d25b1694136f841f8229eeb0 100644 (file)
@@ -181,6 +181,28 @@ def valid_vdi(func):
         
     return check_vdi_ref
 
+def valid_vtpm(func):
+    """Decorator to verify if vtpm_ref is valid before calling
+    method.
+
+    @param func: function with params: (self, session, vtpm_ref)
+    @rtype: callable object
+    """
+    def check_vtpm_ref(self, session, vtpm_ref, *args, **kwargs):
+        xendom = XendDomain.instance()
+        if type(vtpm_ref) == type(str()) and \
+               xendom.is_valid_dev('vtpm', vtpm_ref):
+            return func(self, session, vtpm_ref, *args, **kwargs)
+        else:
+            return {'Status': 'Failure',
+                    'ErrorDescription': XEND_ERROR_VTPM_INVALID}
+
+    # make sure we keep the 'api' attribute
+    if hasattr(func, 'api'):
+        check_vtpm_ref.api = func.api
+
+    return check_vtpm_ref
+
 def valid_sr(func):
     """Decorator to verify if sr_ref is valid before calling
     method.
@@ -246,6 +268,7 @@ class XendAPI:
             'VBD': (valid_vbd, session_required),
             'VIF': (valid_vif, session_required),
             'VDI': (valid_vdi, session_required),
+            'VTPM':(valid_vtpm, session_required),
             'SR':  (valid_sr, session_required)}
         
         # Cheat methods
@@ -580,8 +603,6 @@ class XendAPI:
         'actions_after_reboot',
         'actions_after_suspend',
         'actions_after_crash',
-        'TPM_instance',
-        'TPM_backend',
         'bios_boot',
         'platform_std_VGA',
         'platform_serial',
@@ -645,14 +666,6 @@ class XendAPI:
         dom = XendDomain.instance().get_vm_by_uuid(vm_ref)
         return xen_api_success(dom.get_vtpms())
     
-    def vm_get_tpm_instance(self, session, vm_ref):
-        dom = XendDomain.instance().get_vm_by_uuid(vm_ref)
-        return xen_api_todo() # unsupported by xc
-    
-    def vm_get_tpm_backend(self, session, vm_ref):
-        dom = XendDomain.instance().get_vm_by_uuid(vm_ref)
-        return xen_api_todo() # unsupported by xc
-    
     def vm_get_pci_bus(self, session, vm_ref):
         dom = XendDomain.instance().get_vm_by_uuid(vm_ref)
         return xen_api_todo() # unsupported by xc
@@ -1262,6 +1275,49 @@ class XendAPI:
         return xen_api_error(XEND_ERROR_VDI_INVALID)
 
 
+    # Xen API: Class VTPM
+    # ----------------------------------------------------------------
+
+    VTPM_attr_ro = [ ]
+    VTPM_attr_rw = ['type',
+                    'VM',
+                    'backend',
+                    'instance']
+
+    VTPM_attr_inst = VTPM_attr_rw
+
+    # object methods
+    def vtpm_get_record(self, session, vtpm_ref):
+        xendom = XendDomain.instance()
+        vm = xendom.get_vm_with_dev_uuid('vtpm', vtpm_ref)
+        if not vm:
+            return xen_api_error(XEND_ERROR_VTPM_INVALID)
+        cfg = vm.get_dev_xenapi_config('vtpm', vtpm_ref)
+        if not cfg:
+            return xen_api_error(XEND_ERROR_VTPM_INVALID)
+        valid_vtpm_keys = self.VTPM_attr_ro + self.VTPM_attr_rw + \
+                          self.Base_attr_ro + self.Base_attr_rw
+        for k in cfg.keys():
+            if k not in valid_vtpm_keys:
+                del cfg[k]
+
+        return xen_api_success(cfg)
+
+    # class methods
+    def vtpm_create(self, session, vtpm_struct):
+        xendom = XendDomain.instance()
+        if xendom.is_valid_vm(vtpm_struct['VM']):
+            dom = xendom.get_vm_by_uuid(vtpm_struct['VM'])
+            try:
+                vtpm_ref = dom.create_vtpm(vtpm_struct)
+                xendom.managed_config_save(dom)
+                return xen_api_success(vtpm_ref)
+            except XendError:
+                return xen_api_error(XEND_ERROR_TODO)
+        else:
+            return xen_api_error(XEND_ERROR_DOMAIN_INVALID)
+
+
     # Xen API: Class SR
     # ----------------------------------------------------------------
     SR_attr_ro = ['VDIs',
index 7bed6d676c10fd57504a671c601c261b42a707e1..0787ebd79fd758b57fcad33f47a4a8da4d3f39b7 100644 (file)
@@ -110,8 +110,6 @@ XENAPI_UNSUPPORTED_IN_LEGACY_CFG = [
     'vcpus_features_force_on',
     'vcpus_features_force_off',
     'actions_after_suspend',
-    'tpm_instance',
-    'tpm_backends',
     'bios_boot',
     'platform_std_vga',
     'platform_serial',
@@ -570,11 +568,14 @@ class XendConfig(dict):
         # ------------------
         cfg['vif_refs'] = []
         cfg['vbd_refs'] = []
+        cfg['vtpm_refs'] = []
         for dev_uuid, (dev_type, dev_info) in cfg['device'].items():
             if dev_type == 'vif':
                 cfg['vif_refs'].append(dev_uuid)
             elif dev_type in ('vbd','tap'):
                 cfg['vbd_refs'].append(dev_uuid)
+            elif dev_type == 'vtpm':
+                cfg['vtpm_refs'].append(dev_uuid)
                 
         return cfg
 
@@ -610,6 +611,8 @@ class XendConfig(dict):
             cfg['vif_refs'] = []
         if 'vbd_refs' not in cfg:
             cfg['vbd_refs'] = []
+        if 'vtpm_refs' not in cfg:
+            cfg['vtpm_refs'] = []
 
         return cfg
 
@@ -747,6 +750,8 @@ class XendConfig(dict):
             self['vif_refs'] = []
         if 'vbd_refs' not in self:
             self['vbd_refs'] = []
+        if 'vtpm_refs' not in self:
+            self['vtpm_refs'] = []
 
     def device_add(self, dev_type, cfg_sxp = None, cfg_xenapi = None):
         if dev_type not in XendDevices.valid_devices():
@@ -815,7 +820,16 @@ class XendConfig(dict):
                 self['device'][dev_uuid] = (dev_type, dev_info)
                 self['vbd_refs'].append(dev_uuid)                
                 return dev_uuid
-            
+
+            elif dev_type == 'vtpm':
+                if cfg_xenapi.get('type'):
+                    dev_info['type'] = cfg_xenapi.get('type')
+                dev_uuid = cfg_xenapi.get('uuid', uuid.createString())
+                dev_info['uuid'] = dev_uuid
+                self['device'][dev_uuid] = (dev_type, dev_info)
+                self['vtpm_refs'].append(dev_uuid)
+                return dev_uuid
+
             elif dev_type == 'tap':
                 dev_info['uname'] = 'tap:qcow:%s' % cfg_xenapi.get('image')
                 dev_info['dev'] = '%s:disk' % cfg_xenapi.get('device')
index 721edad3033c1ffc1475ead654137790715aa3d6..46d4c78e22d78fa371cfe60cca7f703ac4423038 100644 (file)
@@ -1897,6 +1897,24 @@ class XendDomainInfo:
 
         return dev_uuid
 
+    def create_vtpm(self, xenapi_vtpm):
+        """Create a VTPM device from the passed struct in Xen API format.
+
+        @return: uuid of the device
+        @rtype: string
+        """
+
+        dev_uuid = self.info.device_add('vtpm', cfg_xenapi = xenapi_vtpm)
+        if not dev_uuid:
+            raise XendError('Failed to create device')
+
+        if self.state in (DOM_STATE_HALTED,):
+            sxpr = self.info.device_sxpr(dev_uuid)
+            devid = self.getDeviceController('vtpm').createDevice(sxpr)
+            raise XendError("Device creation failed")
+
+        return dev_uuid
+
     def has_device(self, dev_class, dev_uuid):
         return (dev_uuid in self.info['%s_refs' % dev_class])
 
index e7e274ff1ca15862c93852a24cb7dbfc378e1434..59471452672e8a1ed6b31936df2e1277127837ee 100644 (file)
@@ -47,6 +47,7 @@ XEND_ERROR_UNSUPPORTED           = ('EUNSUPPORTED', 'Method Unsupported')
 XEND_ERROR_VM_INVALID            = ('EVMINVALID', 'VM Invalid')
 XEND_ERROR_VBD_INVALID           = ('EVBDINVALID', 'VBD Invalid')
 XEND_ERROR_VIF_INVALID           = ('EVIFINVALID', 'VIF Invalid')
+XEND_ERROR_VTPM_INVALID          = ('EVTPMINVALID', 'VTPM Invalid')
 XEND_ERROR_VDI_INVALID           = ('EVDIINVALID', 'VDI Invalid')
 XEND_ERROR_SR_INVALID           = ('ESRINVALID', 'SR Invalid')
 XEND_ERROR_TODO                  = ('ETODO', 'Lazy Programmer Error')
index 6f6ab93b1a92f59cbb0e3be48fb47c571035f504..c313efe2a899a057a7afa7ed338d5751390f4349 100644 (file)
@@ -49,22 +49,37 @@ class TPMifController(DevController):
         if inst == -1:
             inst = int(sxp.child_value(config, 'instance' , '0'))
 
+        typ    = sxp.child_value(config, 'type')
+        uuid   = sxp.child_value(config, 'uuid')
+
         log.info("The domain has a TPM with pref. instance %d and devid %d.",
                  inst, devid)
         back  = { 'pref_instance' : "%i" % inst,
                   'resume'        : "%s" % (self.vm.getResume()) }
+        if typ:
+            back['type'] = typ
+        if uuid:
+            back['uuid'] = uuid
+
         front = { 'handle' : "%i" % devid }
 
         return (devid, back, front)
 
-    def configuration(self, devid):
-
-        result = DevController.configuration(self, devid)
+    def getDeviceConfiguration(self, devid):
+        """Returns the configuration of a device"""
+        result = DevController.getDeviceConfiguration(self, devid)
 
-        instance = self.readBackend(devid, 'instance')
+        (instance, uuid, type) = \
+                           self.readBackend(devid, 'instance',
+                                                   'uuid',
+                                                   'type')
 
         if instance:
-            result.append(['instance', instance])
+            result['instance'] = instance
+        if uuid:
+            result['uuid'] = uuid
+        if type:
+            result['type'] == type
 
         return result
 
index 7b43ee79daa5a0604153cf68b009d411ba4bbdd4..aab0d930ecee9e163c0f64b2a7351345e6bea659 100644 (file)
@@ -291,7 +291,7 @@ gopts.var('vif', val="type=TYPE,mac=MAC,bridge=BRIDGE,ip=IPADDR,script=SCRIPT,ba
           This option may be repeated to add more than one vif.
           Specifying vifs will increase the number of interfaces as needed.""")
 
-gopts.var('vtpm', val="instance=INSTANCE,backend=DOM",
+gopts.var('vtpm', val="instance=INSTANCE,backend=DOM,type=TYPE",
           fn=append_value, default=[],
           use="""Add a TPM interface. On the backend side use the given
           instance as virtual TPM instance. The given number is merely the
@@ -299,7 +299,11 @@ gopts.var('vtpm', val="instance=INSTANCE,backend=DOM",
           which instance number will actually be assigned to the domain.
           The associtation between virtual machine and the TPM instance
           number can be found in /etc/xen/vtpm.db. Use the backend in the
-          given domain.""")
+          given domain.
+          The type parameter can be used to select a specific driver type
+          that the VM can use. To prevent a fully virtualized domain (HVM)
+          from being able to access an emulated device model, you may specify
+          'paravirtualized' here.""")
 
 gopts.var('access_control', val="policy=POLICY,label=LABEL",
           fn=append_value, default=[],
@@ -585,27 +589,28 @@ def configure_vtpm(config_devs, vals):
     """Create the config for virtual TPM interfaces.
     """
     vtpm = vals.vtpm
-    vtpm_n = 1
-    for idx in range(0, vtpm_n):
-        if idx < len(vtpm):
-            d = vtpm[idx]
-            instance = d.get('instance')
-            if instance == "VTPMD":
-                instance = "0"
-            else:
-                if instance != None:
-                    try:
-                        if int(instance) == 0:
-                            err('VM config error: vTPM instance must not be 0.')
-                    except ValueError:
-                        err('Vm config error: could not parse instance number.')
-            backend = d.get('backend')
-            config_vtpm = ['vtpm']
-            if instance:
-                config_vtpm.append(['pref_instance', instance])
-            if backend:
-                config_vtpm.append(['backend', backend])
-            config_devs.append(['device', config_vtpm])
+    if len(vtpm) > 0:
+        d = vtpm[0]
+        instance = d.get('instance')
+        if instance == "VTPMD":
+            instance = "0"
+        else:
+            if instance != None:
+                try:
+                    if int(instance) == 0:
+                        err('VM config error: vTPM instance must not be 0.')
+                except ValueError:
+                    err('Vm config error: could not parse instance number.')
+        backend = d.get('backend')
+        typ = d.get('type')
+        config_vtpm = ['vtpm']
+        if instance:
+            config_vtpm.append(['pref_instance', instance])
+        if backend:
+            config_vtpm.append(['backend', backend])
+        if typ:
+            config_vtpm.append(['type', type])
+        config_devs.append(['device', config_vtpm])
 
 
 def configure_vifs(config_devs, vals):